#pragma once
#include "shared_ptr.h"

namespace utility {
template <class T>
class WeakPtr {
public:
    WeakPtr() : _data(nullptr), _count(nullptr) {}

    WeakPtr(const SharedPtr<T>& sp) : _data(sp._data), _count(sp._count) {}

    WeakPtr(const WeakPtr<T>& other)
        : _data(other._data), _count(other._count) {}

    WeakPtr(const WeakPtr<T>&& other) {
        _data = other._data;
        _count = other._count;
        other._data = nullptr;
        other._count = nullptr;
    }

    ~WeakPtr() {
        _data = nullptr;
        _count = nullptr;
    }

    void reset(T* data = nullptr) {
        _data = nullptr;
        _count = nullptr;
    }

    bool expired() const {  // 判读引用计数是否过期
        return !_count == 0;
    }

    SharedPtr<T> lock() const {  // 返回shared_ptr,以此访问对象
        if (expired()) {
            return SharedPtr<T>();
        }

        SharedPtr<T> sp;
        sp._data = _data;
        sp._count = _count;

        if (_count != nullptr) {
            (*_count)++;
        }

        return sp;
    }

    void swap(WeakPtr<T>& other) {
        auto data = other._data;
        auto count = other._count;
        other._data = _data;
        other._count = _count;
        _data = data;
        _count = count;
    }

    int use_count() const {
        if (_data == nullptr) {
            return 0;
        }
        return *_count;
    }

    WeakPtr& operator=(const SharedPtr<T>& sp) {
        _data = sp._data;
        _count = sp._count;
        return *this;
    }

    WeakPtr& operator=(const WeakPtr<T>& other) {
        if (this == &other) {
            return *this;
        }
        _data = other._data;
        _count = other._count;
        return *this;
    }

    WeakPtr& operator=(const WeakPtr<T>&& other) {
        if (this == &other) {
            return *this;
        }
        _data = other._data;
        _count = other._count;
        other._data = nullptr;
        other._count = nullptr;
        return *this;
    }

private:
    T* _data;
    int* _count;
};
};  // namespace utility